/**
 * Copyright 2000 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 */
package self.amigo.elem.uml;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import self.awt.*;
import self.gee.*;
import self.lang.*;
import self.xml.*;

import self.amigo.elem.*;

import org.w3c.dom.*;


public class LogicalClassView extends ARectangularLinkable {
	
	/**
	 * If the internal state of this class ever changes in such a way that it can't be defaulted,
	 * then the {@link #serialVersionUID} should be incremented to ensure serialized instances cleanly fail.  
	 */
	private static final long serialVersionUID = 1;
	
  final static public String ABSTRACT_PROP = "abstract";
  final static public String NAMECOMPARTMENT_PROP = "NameCompartment";
  final static public String OPERATIONSCOMPARTMENT_PROP = "Operations";
  final static public String ATTRIBUTESCOMPARTMENT_PROP = "Attributes";

  public LogicalClassView() {
    delegate =  constructDelegate();
    setDelegate( delegate );
  }

  protected ARectangularHandledElement constructDelegate() {
    return new Essential();
  }

  class Essential extends ARectangularHandledElement {
  	
	/**
	 * If the internal state of this class ever changes in such a way that it can't be defaulted,
	 * then the {@link #serialVersionUID} should be incremented to ensure serialized instances cleanly fail.  
	 */
	private static final long serialVersionUID = 1;
	
    transient private ICompartmentsRenderInfo     context = new PaintContext();
    private boolean                     isAbstract;
    protected NameCompartmentFeature      nameCompartment = new NameCompartmentFeature();
    private AuxilaryCompartmentFeature  operations = new AuxilaryCompartmentFeature();
    private AuxilaryCompartmentFeature  attributes = new AuxilaryCompartmentFeature();
    private String[]                    attrAndOps = new String[2];
    private boolean[]                   attrAndOpsVis = new boolean[2];
    protected MultiCompartmentPainter   compartmentPainter;

    public Essential() {
      fig.setBounds( 10, 10, 80, 40 );
    }

    public void       setLayer( IDiagramLayer layerToDrawOn, boolean add ) {
      super.setLayer( layerToDrawOn, add );
      compartmentPainter = (MultiCompartmentPainter) PainterManager.getPainterForOwner(
                                          layer, MultiCompartmentPainter.class );
    }

    protected void paintFrame( Graphics surface ) {
      if ( !outlineOnly ) {
//        surface.setColor( Color.white );
        surface.setColor( ArchetypeUtils.getArchetypeColor( nameCompartment.archetypeColor) );

        String symbol = nameCompartment.aidLink;
        boolean paintSymbol = !StringUtils.isNullOrEmpty( symbol );
        if ( paintSymbol )
          SymbolPaintManagerUtils.startSymbol( surface, this, symbol );
        try {
          surface.fillRect( fig.x, fig.y, fig.width, fig.height );
          surface.setColor( frameColor );
          surface.drawRect( fig.x, fig.y, fig.width, fig.height );
        } finally {
          if ( paintSymbol )
            SymbolPaintManagerUtils.endSymbol( surface );
        }
      } else {
        surface.setColor( frameColor );
        surface.drawRect( fig.x, fig.y, fig.width, fig.height );
      }
    }

    public void       paint( Graphics surface ) {
      paintFrame( surface );
      compartmentPainter.paint( surface, context, outlineOnly );
    }

    public void       resize( int x, int y, Point[] handle, MouseEvent e, int dragState ) {
      if ( dragState == IGraphicElement.DS_AFTER_LAST ) {
        super.resize( x, y, handle, e, dragState );
        return;
      }
      layer.beginUpdate();
      super.resize( x, y, handle, e, dragState );
      if ( fig.width < 60 )
        fig.width = 60;
      if ( fig.height < 25 )
        fig.height = 25;
      resetFrame();
      layer.endUpdate();
    }

    // IEditableElement support
    public void       getProperties( Map store ) {
      store.put( ABSTRACT_PROP, (isAbstract? Boolean.TRUE: Boolean.FALSE) );
      store.put( NAMECOMPARTMENT_PROP, nameCompartment.clone() );
      store.put( OPERATIONSCOMPARTMENT_PROP, operations.clone() );
      store.put( ATTRIBUTESCOMPARTMENT_PROP, attributes.clone() );
    }

    public void       setProperties( Map data ) {
      Boolean isAbst = (Boolean) data.get( ABSTRACT_PROP );
      isAbstract = isAbst.booleanValue();
      nameCompartment.set( (NameCompartmentFeature)data.get( NAMECOMPARTMENT_PROP) );
      operations.set( (AuxilaryCompartmentFeature)data.get( OPERATIONSCOMPARTMENT_PROP) );
      attributes.set( (AuxilaryCompartmentFeature)data.get( ATTRIBUTESCOMPARTMENT_PROP) );
      layer.setDirty();
    }

    // IPersistentElement support
    public void readFrom( Node self, HashMap idObjLookUp ) throws DOMException {
      super.readFrom( self, idObjLookUp );
      String abstAsString = DomUtils.getElementAttribute( self, ABSTRACT_PROP );
      isAbstract = BooleanUtils.toValue( abstAsString );
      nameCompartment.readFrom( self, idObjLookUp );

      Node attr = DomUtils.getChildElementNode( self, ATTRIBUTESCOMPARTMENT_PROP );
      attributes.readFrom( attr, idObjLookUp );

      Node ops = DomUtils.getChildElementNode( self, OPERATIONSCOMPARTMENT_PROP );
      operations.readFrom( ops, idObjLookUp );
    }

    public void writeTo( Document doc, Element self, HashMap objIdLookup ) throws DOMException {
      super.writeTo( doc, self, objIdLookup );
      DomUtils.setElementAttribute( self, ABSTRACT_PROP, "" + isAbstract );
      nameCompartment.writeTo( doc, self, objIdLookup );

      Element attr = doc.createElement( ATTRIBUTESCOMPARTMENT_PROP );
      self.appendChild( attr );
      attributes.writeTo( doc, attr, objIdLookup );

      Element ops = doc.createElement( OPERATIONSCOMPARTMENT_PROP );
      self.appendChild( ops );
      operations.writeTo( doc, ops, objIdLookup );
    }

    class PaintContext implements ICompartmentsRenderInfo {
      public Rectangle  getBounds() {
        return fig;
      }

      public String     getName() {
        return nameCompartment.name;
      }

      public String     getSymbol() {
        return StringUtils.toNullOrNonEmptyValue( nameCompartment.aidLink );
      }

      public boolean    isNameUnderlined() {
        return false;
      }

      public boolean    isNameItalic() {
        return isAbstract;
      }

      public String     getStereoType() {
        return StringUtils.toNullOrNonEmptyValue( nameCompartment.stereotype );
      }

      public String     getNamespace() {
        return StringUtils.toNullOrNonEmptyValue( nameCompartment.nameSpace );
      }

      public boolean[] getVisibleAuxilaryCompartments() {
        attrAndOpsVis[0] = attributes.visible;
        attrAndOpsVis[1] = operations.visible;
        return attrAndOpsVis;
      }

      public String[]  getAuxilaryCompartments() {
        attrAndOps[0] = attributes.details;
        attrAndOps[1] = operations.details;
        return attrAndOps;
      }
    }
  }
}
